package blockchain

import (
	"aqchain/pkg/blockchain/contract/auction"
	"aqchain/pkg/log"
	"aqchain/pkg/model"
	"context"
	"gitee.com/aqchain/go-ethereum/accounts/abi/bind"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

func (c *Client) SubscribeAuctionContractEvent(ctx context.Context) error {
	createChan := make(chan *auction.AuctionContractCreate)
	bidChan := make(chan *auction.AuctionContractBid)
	finishChan := make(chan *auction.AuctionContractFinish)
	createSub, err := c.auctionContract.WatchCreate(&bind.WatchOpts{Context: ctx}, createChan, nil)
	if err != nil {
		return err
	}
	defer createSub.Unsubscribe()
	bidSub, err := c.auctionContract.WatchBid(&bind.WatchOpts{Context: ctx}, bidChan, nil)
	if err != nil {
		return err
	}
	defer bidSub.Unsubscribe()
	finishSub, err := c.auctionContract.WatchFinish(&bind.WatchOpts{Context: ctx}, finishChan, nil)
	if err != nil {
		return err
	}
	defer finishSub.Unsubscribe()

	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case err = <-createSub.Err():
			return err
		case err = <-bidSub.Err():
			return err
		case err = <-finishSub.Err():
			return err
		case event := <-createChan:
			err = c.handleCreateAuction(event)
			if err != nil {
				return err
			}
		case event := <-bidChan:
			err = c.handleBidAuction(event)
			if err != nil {
				return err
			}
		case event := <-finishChan:
			err = c.handleFinishAuction(event)
			if err != nil {
				return err
			}
		}
	}
}

func (c *Client) handleCreateAuction(event *auction.AuctionContractCreate) error {
	block, err := c.client.BlockByHash(context.Background(), event.Raw.BlockHash)
	if err != nil {
		return err
	}
	var itemRecord model.Item
	err = c.db.Where(&model.Item{DCI: event.Dci}).First(&itemRecord).Error
	if err != nil {
		return err
	}
	err = c.db.Transaction(func(tx *gorm.DB) error {
		newAuction := model.Auction{
			DCI:          event.Dci,
			Seller:       event.Seller.String(),
			Deadline:     event.Deadline.String(),
			ReservePrice: event.ReservePrice.String(),
			BlockNumber:  event.Raw.BlockNumber,
			BlockTime:    block.Time().Uint64(),
		}
		err = c.db.Create(&newAuction).Error
		if err != nil {
			return err
		}
		newEvent := model.AuctionEvent{
			TxHash:      event.Raw.TxHash.String(),
			DCI:         event.Dci,
			From:        event.Seller.String(),
			Value:       event.ReservePrice.String(),
			EventName:   "create",
			BlockNumber: event.Raw.BlockNumber,
			BlockTime:   block.Time().Uint64(),
		}
		err = c.db.Create(&newEvent).Error
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return err
	}
	log.Logger.Debug("接收到拍卖交易创建事件", zap.String("DCI", event.Dci), zap.String("Seller", event.Seller.String()), zap.String("Deadline", event.Deadline.String()), zap.String("ReservePrice", event.ReservePrice.String()))
	return nil
}

func (c *Client) handleBidAuction(event *auction.AuctionContractBid) error {
	block, err := c.client.BlockByHash(context.Background(), event.Raw.BlockHash)
	if err != nil {
		return err
	}
	var itemRecord model.Item
	err = c.db.Where(&model.Item{DCI: event.Dci}).First(&itemRecord).Error
	if err != nil {
		return err
	}
	err = c.db.Transaction(func(tx *gorm.DB) error {
		auctionRecord := model.Auction{
			DCI:           event.Dci,
			HighestBid:    event.Bid.String(),
			HighestBidder: event.Bidder.String(),
		}
		err = c.db.Model(&auctionRecord).Updates(&auctionRecord).Error
		if err != nil {
			return err
		}
		newEvent := model.AuctionEvent{
			TxHash:      event.Raw.TxHash.String(),
			DCI:         event.Dci,
			From:        event.Bidder.String(),
			Value:       event.Bid.String(),
			EventName:   "bid",
			BlockNumber: event.Raw.BlockNumber,
			BlockTime:   block.Time().Uint64(),
		}
		err = c.db.Create(&newEvent).Error
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return err
	}
	log.Logger.Debug("接收到拍卖交易出价事件", zap.String("DCI", event.Dci), zap.String("Bidder", event.Bidder.String()), zap.String("Bid", event.Bid.String()))
	return nil
}

func (c *Client) handleFinishAuction(event *auction.AuctionContractFinish) error {
	block, err := c.client.BlockByHash(context.Background(), event.Raw.BlockHash)
	if err != nil {
		return err
	}
	var itemRecord model.Item
	err = c.db.Where(&model.Item{DCI: event.Dci}).First(&itemRecord).Error
	if err != nil {
		return err
	}
	err = c.db.Transaction(func(tx *gorm.DB) error {
		err = c.db.Delete(&model.Auction{DCI: event.Dci}).Error
		if err != nil {
			return err
		}
		newEvent := model.AuctionEvent{
			TxHash:      event.Raw.TxHash.String(),
			DCI:         event.Dci,
			From:        event.Seller.String(),
			Value:       event.HighestBid.String(),
			EventName:   "finish",
			BlockNumber: event.Raw.BlockNumber,
			BlockTime:   block.Time().Uint64(),
		}
		err = c.db.Create(&newEvent).Error
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return err
	}
	log.Logger.Debug("接收到拍卖交易结束事件", zap.String("DCI", event.Dci), zap.String("Seller", event.Seller.String()), zap.String("Bidder", event.HighestBidder.String()), zap.String("Bid", event.HighestBid.String()))
	return nil
}
